{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# §3: NumPy"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "NumPy provides an N-dimentional array type (ndarray), which describes a collection of \"items\" of the same type.\n",
    "\n",
    "Reference\n",
    "\n",
    "https://numpy.org/doc/stable/reference/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'numpy.ndarray'>\n",
      "(2, 3)\n",
      "int32\n",
      "[[1 2 3]\n",
      " [4 5 6]]\n",
      "3\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "a = np.array([[1,2,3],[4,5,6]])\n",
    "print(type(a))\n",
    "print(a.shape)\n",
    "print(a.dtype)\n",
    "print(a)\n",
    "print(a[0,2])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.1 Constructing arrays\n",
    "\n",
    "construct by list or tuple\n",
    "\n",
    "class numpy.ndarray(shape, dtype=float, buffer=None, offset=0, strides=None, order=None)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1. 2. 3.]\n",
      " [4. 5. 6.]]\n",
      "[1.+0.j 2.+0.j]\n"
     ]
    }
   ],
   "source": [
    "a = np.array([[1,2,3],[4,5,6]], dtype='float')\n",
    "b = np.array([1,2], dtype=complex)\n",
    "print(a)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "by built in function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[[ 0  1  2  3]\n",
      "  [ 4  5  6  7]\n",
      "  [ 8  9 10 11]]\n",
      "\n",
      " [[12 13 14 15]\n",
      "  [16 17 18 19]\n",
      "  [20 21 22 23]]]\n",
      "[0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]\n",
      "[ 1.  4. 16.]\n"
     ]
    }
   ],
   "source": [
    "c = np.arange(24).reshape(2,3,4)\n",
    "d = np.linspace(0,1,10,endpoint=False)\n",
    "e = np.logspace(0,4,3,base=2)\n",
    "print(c)\n",
    "print(d)\n",
    "print(e)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[-1  0  1]\n",
      " [-1  0  1]\n",
      " [-1  0  1]]\n",
      "[[-2 -2 -2]\n",
      " [ 0  0  0]\n",
      " [ 2  2  2]]\n",
      "[[0]\n",
      " [1]\n",
      " [2]]\n",
      "[[0 1 2]]\n",
      "[[0 0 0]\n",
      " [1 1 1]\n",
      " [2 2 2]]\n",
      "[[0 1 2]\n",
      " [0 1 2]\n",
      " [0 1 2]]\n"
     ]
    }
   ],
   "source": [
    "#multi-dimention grid\n",
    "x = np.array([-1,0,1])\n",
    "y = np.array([-2,0,2])\n",
    "X, Y = np.meshgrid(x,y)\n",
    "print(X)\n",
    "print(Y)\n",
    "\n",
    "x,y = np.ogrid[:3, :3]\n",
    "print(x) #(3,1)\n",
    "print(y) #(1,3)\n",
    "\n",
    "x,y = np.mgrid[:3, :3]\n",
    "print(x)\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "construct special array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0. 0. 0.]\n",
      " [0. 0. 0.]]\n",
      "[[0. 0. 0.]\n",
      " [0. 0. 0.]]\n",
      "[[1 1 1]\n",
      " [1 1 1]]\n",
      "[[0. 0. 0.]\n",
      " [0. 0. 0.]]\n"
     ]
    }
   ],
   "source": [
    "print(np.zeros((2,3)))\n",
    "print(np.zeros_like(a))\n",
    "print(np.ones((2,3),dtype=np.int16))\n",
    "print(np.empty((2,3)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1. 0. 0.]\n",
      " [0. 1. 0.]\n",
      " [0. 0. 1.]]\n",
      "[[1. 0. 0.]\n",
      " [0. 1. 0.]\n",
      " [0. 0. 1.]]\n",
      "[[0. 1. 0.]\n",
      " [0. 0. 1.]\n",
      " [0. 0. 0.]]\n",
      "[[0. 0. 0.]\n",
      " [1. 0. 0.]\n",
      " [0. 1. 0.]]\n"
     ]
    }
   ],
   "source": [
    "print(np.identity(3))\n",
    "print(np.eye(3)) #k=0\n",
    "print(np.eye(3, k=1))\n",
    "print(np.eye(3, k=-1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 0 0]\n",
      " [0 2 0]\n",
      " [0 0 3]]\n",
      "[1 2 3]\n"
     ]
    }
   ],
   "source": [
    "f = np.diag([1,2,3])\n",
    "print(f)\n",
    "print(np.diag(f))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.33895982 0.60277519 0.05996789]\n",
      " [0.26436115 0.96813115 0.9997349 ]]\n",
      "[[-1.46190166  0.8826478   0.25615856]\n",
      " [ 1.78733883 -1.36295713 -0.25882063]]\n",
      "[[-0.53575848  1.00370096 -2.982441  ]\n",
      " [-1.67710203  0.20053417  0.01666187]]\n"
     ]
    }
   ],
   "source": [
    "print(np.random.random((2,3))) #[0,1]\n",
    "print(np.random.normal(loc=0.0, scale=1, size=(2, 3)))\n",
    "print(np.random.randn(2,3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "from string, function or iteration"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 2]\n",
      "[ 1  2 16]\n",
      "[[ 1.  2.  3.  4.  5.]\n",
      " [ 2.  4.  6.  8. 10.]\n",
      " [ 3.  6.  9. 12. 15.]\n",
      " [ 4.  8. 12. 16. 20.]\n",
      " [ 5. 10. 15. 20. 25.]]\n",
      "[0 1 2 3 4]\n"
     ]
    }
   ],
   "source": [
    "#from string\n",
    "print(np.fromstring('1 2', dtype=int, sep=' '))\n",
    "print(np.frombuffer(b'\\x01\\x02\\x10', dtype=np.uint8))\n",
    "\n",
    "#from function\n",
    "print(np.fromfunction(lambda i,j:(i+1)*(j+1), (5,5)))\n",
    "\n",
    "#from iteration\n",
    "it = range(5)\n",
    "print(np.fromiter(it, dtype=np.int32))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.2 save & load"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2 3]\n",
      " [4 5 6]]\n",
      "['arr_0', 'arr_1']\n",
      "[[1 2 3]\n",
      " [4 5 6]]\n",
      "['a', 'd']\n",
      "[[1 2 3]\n",
      " [4 5 6]]\n",
      "[[1. 2. 3.]\n",
      " [4. 5. 6.]]\n",
      "[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]\n"
     ]
    }
   ],
   "source": [
    "np.save('a.npy',a)\n",
    "a_load = np.load('a.npy')\n",
    "print(a_load)\n",
    "\n",
    "np.savez('ad.npz',a,d)\n",
    "data = np.load('ad.npz')\n",
    "print(data.files)\n",
    "print(data['arr_0'])\n",
    "\n",
    "np.savez('ad.npz',a=a,d=d)\n",
    "data = np.load('ad.npz')\n",
    "print(data.files)\n",
    "print(data['a'])\n",
    "\n",
    "#from text file\n",
    "np.savetxt('123.txt',a) #save as text\n",
    "f = np.loadtxt('123.txt') #load from text\n",
    "print(f)\n",
    "\n",
    "#from binary file\n",
    "c.tofile('c.bin') #save as binary file\n",
    "c_bin = np.fromfile('c.bin',dtype=np.int32)\n",
    "print(c_bin) #one dimention!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.3 use"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6\n",
      "6\n",
      "[2 5]\n",
      "[[1 3]\n",
      " [4 6]]\n",
      "[4 5 6]\n",
      "[2 5]\n",
      "[1 2 3]\n",
      "[4 5 6]\n",
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "5\n",
      "6\n"
     ]
    }
   ],
   "source": [
    "print(a[1,2])\n",
    "index = (1,2)\n",
    "print(a[index])\n",
    "print(a[0:2,1])\n",
    "print(a[:,[0,2]]) #select the column 0 and 2\n",
    "print(a[1]) #[1, :]\n",
    "print(a[...,1])\n",
    "\n",
    "for row in a:\n",
    "    print(row)\n",
    "for element in a.flat:\n",
    "    print(element)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.4 properties"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "(2, 3)\n",
      "6\n",
      "float64\n",
      "all numpy type: {<class 'numpy.complex128'>, <class 'numpy.timedelta64'>, <class 'numpy.int32'>, <class 'numpy.void'>, <class 'numpy.int64'>, <class 'numpy.longdouble'>, <class 'numpy.uintc'>, <class 'numpy.float16'>, <class 'numpy.uint8'>, <class 'numpy.uint64'>, <class 'numpy.int16'>, <class 'numpy.int8'>, <class 'numpy.uint32'>, <class 'numpy.intc'>, <class 'numpy.object_'>, <class 'numpy.float32'>, <class 'numpy.bool_'>, <class 'numpy.str_'>, <class 'numpy.float64'>, <class 'numpy.datetime64'>, <class 'numpy.uint16'>, <class 'numpy.clongdouble'>, <class 'numpy.complex64'>, <class 'numpy.bytes_'>}\n",
      "8\n",
      "<memory at 0x0000000005B8DF28>\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\ProgramData\\Anaconda3\\lib\\site-packages\\ipykernel_launcher.py:5: DeprecationWarning: `np.typeDict` is a deprecated alias for `np.sctypeDict`.\n",
      "  \"\"\"\n"
     ]
    }
   ],
   "source": [
    "print(a.ndim) #dimention\n",
    "print(a.shape)\n",
    "print(a.size) #number of elements\n",
    "print(a.dtype) #element type\n",
    "print('all numpy type:',set(np.typeDict.values()))\n",
    "print(a.itemsize) #size of each element\n",
    "print(a.data) #buffer address"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.5 change shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2 3]\n",
      " [4 5 6]]\n",
      "[[1 4]\n",
      " [2 5]\n",
      " [3 6]]\n",
      "[[1 4]\n",
      " [2 5]\n",
      " [3 6]]\n",
      "(2, 3, 4) (4, 2, 3)\n",
      "[[3 6]\n",
      " [2 5]\n",
      " [1 4]]\n",
      "[[3 2 1]\n",
      " [6 5 4]]\n",
      "[[4 5 6]\n",
      " [1 2 3]]\n"
     ]
    }
   ],
   "source": [
    "print(a)\n",
    "print(a.T)\n",
    "print(a.transpose())\n",
    "print(c.shape, c.transpose(2,0,1).shape)\n",
    "\n",
    "print(np.rot90(a)) #rotate anti-clockwise\n",
    "print(np.fliplr(a)) #inverse row elements\n",
    "print(np.flipud(a)) #invers column elements"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1. 2. 3. 4. 5. 6.]\n",
      "(2, 2, 6)\n",
      "(2, 2, 1, 6)\n",
      "(2, 2, 6)\n",
      "(4, 6)\n"
     ]
    }
   ],
   "source": [
    "print(a.ravel()) #ravel to one dimention. same as flatten\n",
    "c.shape = 2,2,-1 #the dimintion of -1 will automatic calculated\n",
    "print(c.shape)\n",
    "c2 = c[:,:,np.newaxis,:] #add new dimention\n",
    "print(c2.shape)\n",
    "print(c2.squeeze().shape) #delete dimention of size 1\n",
    "c3 = c.reshape(4,6) #It does not change the address of elements\n",
    "print(c3.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.6 modify\n",
    "\n",
    "copy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1. 2. 3.]\n",
      " [4. 5. 6.]]\n",
      "True\n",
      "[[7. 2. 3.]\n",
      " [4. 5. 6.]]\n",
      "False\n",
      "[[1. 2. 3.]\n",
      " [4. 5. 6.]]\n",
      "False\n",
      "[[1. 2. 3.]\n",
      " [4. 5. 6.]]\n"
     ]
    }
   ],
   "source": [
    "print(a)\n",
    "p = a #p is same with a\n",
    "print(p is a)\n",
    "p[0,0] = 7\n",
    "print(a)\n",
    "q = a.view() #q is different with a, but they share the data\n",
    "print(q is a)\n",
    "q[0,0] = 1\n",
    "print(a)\n",
    "r = a.copy() #deepcopy, r is different with a\n",
    "print(r is a)\n",
    "r[0,0] = 7\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "combination"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2 3]\n",
      " [4 5 6]\n",
      " [0 0 0]\n",
      " [0 0 0]\n",
      " [1 2 3]\n",
      " [4 5 6]]\n",
      "[[1 2 3 0 0 0]\n",
      " [4 5 6 0 0 0]]\n",
      "(2, 2, 3)\n"
     ]
    }
   ],
   "source": [
    "b = np.zeros_like(a) #(2,3)\n",
    "print(np.concatenate((a,b,a),axis=0)) #adding the demention of axis. other dimention are same\n",
    "print(np.concatenate((a,b),axis=1))\n",
    "\n",
    "#all the dimentions of them should same\n",
    "#adding a new axis\n",
    "print(np.stack((a,b),axis=1).shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "split"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[array([[1.],\n",
      "       [4.]]), array([[2.],\n",
      "       [5.]]), array([[3.],\n",
      "       [6.]])]\n"
     ]
    }
   ],
   "source": [
    "print(np.hsplit(a,3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "repeat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 1]\n",
      " [2 2]\n",
      " [3 3]]\n",
      "[[1 2 3]\n",
      " [1 2 3]]\n"
     ]
    }
   ],
   "source": [
    "v = np.array([1,2,3])\n",
    "print(v.repeat(2).reshape(3,2))\n",
    "print(np.tile(v,2).reshape(2,3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.7 operation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "operatoring all elements"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1.  4.  9.]\n",
      " [16. 25. 36.]]\n",
      "[[ 2.  4.  6.]\n",
      " [ 8. 10. 12.]]\n",
      "[[3. 3. 3.]\n",
      " [3. 3. 3.]]\n"
     ]
    }
   ],
   "source": [
    "b = np.ones((2,3)) * 2\n",
    "print(a**2)\n",
    "print(a*b)\n",
    "b *= 1.5\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "multiplication"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "inner:\n",
      "-2.0\n",
      "[[14. 32.]\n",
      " [32. 77.]]\n",
      "[[1. 2. 3.]\n",
      " [4. 5. 6.]]\n",
      "outer\n",
      "[[ 1.  0. -1.]\n",
      " [ 2.  0. -2.]\n",
      " [ 3.  0. -3.]]\n",
      "(24, 210)\n",
      "multiplication\n",
      "[[1. 1.]\n",
      " [4. 1.]]\n",
      "[[1. 1.]\n",
      " [4. 1.]]\n"
     ]
    }
   ],
   "source": [
    "v1 = np.array([1,2,3.])\n",
    "v2 = np.array([1,0,-1.])\n",
    "print('inner:')\n",
    "print(np.inner(v1,v2))\n",
    "print(np.inner(a,a)) #calculate the inner production of last dimention\n",
    "print(a)\n",
    "\n",
    "print('outer')\n",
    "print(np.outer(v1,v2))\n",
    "c = c.reshape(2,3,4)\n",
    "c2 = np.random.random((5,6,7))\n",
    "print(np.outer(c,c2).shape) #(2*3*4, 5*6*7)\n",
    "\n",
    "f = np.array([[1,0],[0,-1],[0,1]])\n",
    "print('multiplication')\n",
    "print(np.matmul(a,f))\n",
    "print(a@f) #The @ operator can be used as a shorthand for np.matmul on ndarrays."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "dot\n",
    "\n",
    "    If both a and b are 1-D arrays, it is inner product of vectors (without complex conjugation).\n",
    "\n",
    "    If both a and b are 2-D arrays, it is matrix multiplication, but using matmul or a @ b is preferred.\n",
    "\n",
    "    If either a or b is 0-D (scalar), it is equivalent to multiply and using numpy.multiply(a, b) or a * b is preferred.\n",
    "\n",
    "    If a is an N-D array and b is a 1-D array, it is a sum product over the last axis of a and b.\n",
    "\n",
    "    If a is an N-D array and b is an M-D array (where M>=2), it is a sum product over the last axis of a and the second-to-last axis of b:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-2.0\n",
      "[14. 32.]\n",
      "[[1. 1.]\n",
      " [4. 1.]]\n",
      "(3, 4, 5, 7, 8)\n"
     ]
    }
   ],
   "source": [
    "print(np.dot(v1,v2))\n",
    "print(np.dot(a,v1))\n",
    "print(np.dot(a,f))\n",
    "P = np.random.random((3,4,5,6))\n",
    "Q = np.random.random((7,6,8))\n",
    "print(np.dot(P,Q).shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "logical operator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1. 2. 3.]\n",
      " [4. 5. 6.]]\n",
      "[[3. 3. 3.]\n",
      " [3. 3. 3.]]\n",
      "[[False False  True]\n",
      " [False False False]]\n",
      "True\n",
      "False\n",
      "[[ True  True  True]\n",
      " [False False False]]\n"
     ]
    }
   ],
   "source": [
    "print(a)\n",
    "print(b)\n",
    "print(a==b)\n",
    "print(np.any(a==b))\n",
    "print(np.all(a>b))\n",
    "print(np.logical_or(a==b, a<b))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 1 1] [0 1 2]\n",
      "[4 5 6]\n",
      "[[-1 -2 -3]\n",
      " [ 8 10 12]]\n",
      "[[ -1  -2 100]\n",
      " [  8  10  12]]\n",
      "(array([0, 0, 1, 1, 2, 2], dtype=int64), array([0, 2, 0, 2, 0, 2], dtype=int64))\n"
     ]
    }
   ],
   "source": [
    "idx0, idx1 = np.where(a>3)\n",
    "print(idx0, idx1)\n",
    "print(a[idx0,idx1])\n",
    "print(np.where(a>3, a*2, -a))\n",
    "\n",
    "print(np.select([a<3,a>3], [-a,a*2], default=100))\n",
    "\n",
    "print(np.nonzero(X))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.8 function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.10899996757507324\n",
      "3.562999963760376\n"
     ]
    }
   ],
   "source": [
    "#universal function (ufunc)\n",
    "u = np.arange(10000000)\n",
    "from time import time\n",
    "from math import sin\n",
    "\n",
    "t = time()\n",
    "np.sin(u)\n",
    "print(time() - t)\n",
    "\n",
    "t = time()\n",
    "u2 = np.empty(u.shape, dtype='float64')\n",
    "for i in range(u.shape[0]):\n",
    "    u2[i] = sin(u[i])\n",
    "print(time()-t)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "21\n",
      "[5 7 9]\n",
      "6 4\n",
      "[1 2 3 4 5 6]\n",
      "[4 1 0 3 5 2]\n",
      "[ 6 15]\n",
      "[[ 1  3  6]\n",
      " [ 4  9 15]]\n"
     ]
    }
   ],
   "source": [
    "print(a.sum())\n",
    "print(a.sum(axis=0))\n",
    "\n",
    "s = np.array([3,2,6,4,1,5])\n",
    "print(s.max(), s.argmin()) #a.func() is same as np.func(a)\n",
    "\n",
    "print(np.sort(s)) #sort each line\n",
    "print(np.argsort(s))\n",
    "\n",
    "print(np.add.reduce(a,axis=1))\n",
    "print(np.add.accumulate(a,axis=1)) #store the middle results"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "statistics functions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3.5\n",
      "2.9166666666666665\n",
      "1.707825127659933\n",
      "[[1. 1.]\n",
      " [1. 1.]]\n",
      "[0 2 7 2 5 4 0 2]\n",
      "(array([0, 2, 4, 5, 7]), array([0, 1, 5, 4, 2], dtype=int64))\n",
      "[2 0 3 0 1 1 0 1]\n"
     ]
    }
   ],
   "source": [
    "print(a.mean())\n",
    "print(a.var())\n",
    "print(a.std())\n",
    "print(np.cov(a))\n",
    "\n",
    "g = np.random.randint(0,10,8)\n",
    "print(g)\n",
    "print(np.unique(g, return_index=True))\n",
    "print(np.bincount(g)) #missing values are 0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.9 broadcast"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(2, 3, 4)\n",
      "(6, 5)\n",
      "[[1 2 3]\n",
      " [4 5 6]]\n",
      "[[101 202 303]\n",
      " [104 205 306]]\n"
     ]
    }
   ],
   "source": [
    "'''\n",
    "When using the ufunc function to calculate two arrays, \n",
    "the ufunc function will calculate the corresponding elements of these two arrays, \n",
    "so it requires that the two arrays have the same shape.\n",
    "\n",
    "If the shapes are different, the following broadcasting processing will be performed:\n",
    "\n",
    "1. All input arrays should be aligned with the array with the largest dimension, \n",
    "and the insufficient part of the shape attribute should be filled by adding 1 to the front.\n",
    "\n",
    "2. The shape attribute of the output array is the maximum value on each axis of the shape \n",
    "attribute of the input array.\n",
    "\n",
    "3. If the length of an axis of the input array is 1 or the same as the length of the \n",
    "corresponding axis of the output array, the array can be used for calculation, otherwise \n",
    "an error occurs.\n",
    "\n",
    "4. When the length of an axis of the input array is 1, the first group of values \n",
    "on this axis will be used for operations along this axis.\n",
    "'''\n",
    "#(2,3,4) + (3,4) = (2,3,4) + (1,3,4)\n",
    "print((np.random.randn(2,3,4) + np.random.randn(3,4)).shape)\n",
    "#print((np.random.randn(2,3,4) + np.random.randn(5,3,4)).shape)\n",
    "\n",
    "#(6,1) + (1,5) = (6,5)\n",
    "print((np.random.randn(6,1) + np.random.randn(1,5)).shape)\n",
    "\n",
    "print(a)\n",
    "a2 = np.array([100,200,300])\n",
    "print(a+a2) #(2,3) + (1,3) = (2,3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Homework\n",
    "\n",
    "1. Find the most frequently occurring value in the array np. array ([7,2,10,2,7,2,4,9,4,9,8]).\n",
    "\n",
    "2. Create a matrix of 5 * 5, with values in each row ranging from 0 to 4.\n",
    "\n",
    "3. Given an array [5, 4, 3, 1], how can I obtain a new array with 4 zeros inserted between each element of this array?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
